import datetime
import json
from flask import current_app, make_response
from vsearcher import VSearcher
from app.models.base import BaseModel
from app.models.video import Video
from app.libs.utils import Pager
from urllib import parse


class BaseVO:
    dict_attrs = []   # 为了适配dict（）序列化, 选择哪些key需要被序列化
    model_map_vo = {
        # key: VOClass, 下方的VO有示例| 将指定的key的值，转换为对应的对象
    }
    # 需要URL编码的字段，例如：http://localhost/a/b c/ -> http://localhost/a/b%c/ 不会因为空格浏览器无法访问
    url_attrs = ['url', 'img', 'cw']

    def __init__(self, model: BaseModel):
        self.__set_attr(model=model)

    @staticmethod
    def __json_dumps_default_func(o):

        if isinstance(o, list):  # 有些list不是常规的list
            return o
        if isinstance(o, BaseVO):
            return dict(o)
        if hasattr(o, '__dict__'):  # 应该判断属性是否存在
            return o.__dict__
        if isinstance(o, datetime.datetime):
            return o.isoformat().split('T')
        tp = str(type(o))
        if tp.find('float') != -1:  # 兼容numpy类型
            return float(o)
        if tp.find('array') != -1:  # 兼容numpy类型
            return o.tolist()
        else:
            return o.__dict__

    def __json_dumps_self(self) -> str:
        # @NOTE 这里脱去外壳，将不能发挥重写的 __getitem__的作用
        # if len(self.dict_attrs) == 1 and isinstance(getattr(self, self.dict_attrs[0]), list):
        #     return json.dumps(getattr(self, self.dict_attrs[0]), default=self.__json_dumps_default_func)
        # dump前url进行编码
        return json.dumps(self, default=self.__json_dumps_default_func)

    def response(self):
        response = make_response()
        response.status_code = 200
        response.headers['Content-Type'] = 'application/json'
        response.data = self.__json_dumps_self()

        # @MODIFYED: 将只有单属性，值为序列进行转换 {"chapters": []} -> []
        if len(self.dict_attrs) == 1 and isinstance(getattr(self, self.dict_attrs[0]), list):
            response.data = json.dumps(json.loads(
                response.data)[self.dict_attrs[0]])
        response.headers['Access-Control-Allow-Origin'] = current_app.config['ACCESS_CONTROL_ALLOW_ORIGIN']
        return response

    def __set_attr(self, model: BaseModel):
        # model中的有些内容是需要懒加载的，如果model.__dict__会直接加载，从而失效

        if len(self.dict_attrs) == 0:  # 全部返回可以不指定
            for k in model.__dict__.keys():
                setattr(self, k, getattr(model, k))

        elif isinstance(model, BaseModel):
            for k in self.dict_attrs:  # 对象.__dict__ 并不会包含非属性的内容
                if hasattr(model, k):
                    setattr(self, k, getattr(model, k))
        else:
            for k in self.dict_attrs:  # 对象.__dict__ 并不会包含非属性的内容
                if hasattr(model, k):
                    setattr(self, k, getattr(model, k))
            # raise RuntimeError('传入的model不属于BaseModel！')

    def keys(self):  # 为了适配dict（）序列化
        return self.dict_attrs or self.__dict__.keys()  # 不设置默认所有属性全返回

    def __getitem__(self, key):
        item = getattr(self, key)
        # @NOTE
        if item is None:
            return item
        if key in self.url_attrs:
            local_path = item
            source_path = local_path.replace(  # 作用： http://服务器域名/xxx  -> 得到内容 /xxx
                VSearcher.config.args.url_prefix, '').replace('\\', '/')  # 获取路径 排除域名，域名不能进行编码否则容易出问题
            # 讲 /xxx的内容进行
            return f'{VSearcher.config.args.url_prefix}{parse.quote(source_path)}'
        if key in self.model_map_vo.keys():
            if isinstance(item, list):
                return [self.model_map_vo[key](model) for model in item]
            else:
                return self.model_map_vo[key](item)
            # 为了适配dict（）序列化
        return item


# 定义前端成功的响应体

class TokenVO(BaseVO):
    """ 由于没有对应的Model类，所以需要自己初始化属性 """
    # dict_attrs = ['token', 'msg'] # 不设置默认所有属性全返回

    def __init__(self, token, msg=None):
        self.token = token
        self.msg = msg


class FrameVO(BaseVO):
    dict_attrs = ['id', 'name', 'img', 'ms', 'time']


class VideoVO(BaseVO):
    dict_attrs = ['id', 'name', 'url', 'img',
                  'chapter_id', 'kfs', 'cw', 'create_time']
    model_map_vo = {
        'kfs': FrameVO
    }

    def __init__(self, model: Video):
        super(VideoVO, self).__init__(model)


class VideoPureVO(BaseVO):
    dict_attrs = ['id', 'name', 'img', 'create_time']  # 或许可以给一个路径

    # 拷贝过程，会has


class VideoPureListVO(BaseVO):
    dict_attrs = ['videos', 'pager']
    model_map_vo = {
        'videos': VideoPureVO
    }

    def __init__(self, videos: list, pager: Pager):
        self.videos = videos
        self.pager = pager


class ChapterVO(BaseVO):
    dict_attrs = ['id', 'name', 'img', 'course_id', 'videos', 'create_time']
    model_map_vo = {
        'videos': VideoPureVO
    }


class ChapterPureVO(BaseVO):
    dict_attrs = ['id', 'name', 'img', 'course_id', 'create_time']


class ChapterPureListVO(BaseVO):
    dict_attrs = ['chapters', 'pager']
    model_map_vo = {
        'chapters': ChapterPureVO
    }

    def __init__(self, chapters: list, pager: Pager):
        self.chapters = chapters
        self.pager = pager


class CourseVO(BaseVO):
    dict_attrs = ['id', 'name', 'img', 'chapters', 'create_time']
    model_map_vo = {
        'chapters': ChapterPureVO
    }


class CoursePureVO(BaseVO):
    dict_attrs = ['id', 'name', 'img', 'create_time']


class CoursePureListVO(BaseVO):
    dict_attrs = ['courses', 'pager']
    model_map_vo = {
        'courses': CoursePureVO
    }

    def __init__(self, courses: list, pager: Pager):
        self.courses = courses
        self.pager = pager

# class FrameVO(BaseModel):
#     def __init__(self)

# 搜索结果的VO怎么表示呢？先执行，出了结果，再

# ================================================================
# class SearchVO(BaseVO):  # 直接返回就好了， 不需要重新定义,


#     def __init__(self, vs_vo_result, key, r_type):
#         self.key = key
#         self.type = r_type
#         self.result = vs_vo_result


class SFrameVO(BaseVO):
    dict_attrs = ['id', 'name', 'img', 'ms', 'time']


class SVideoVO(BaseVO):
    dict_attrs = ['id', 'name', 'kfs', 'url']
    model_map_vo = {
        'kfs': SFrameVO
    }


class SChapterVO(BaseVO):
    dict_attrs = ['id', 'name', 'videos']
    model_map_vo = {
        'videos': SVideoVO
    }


class SCourseVO(BaseVO):
    dict_attrs = ['id', 'name', 'chapters']
    model_map_vo = {
        'chapters': SChapterVO
    }

# ============================= CatalogVO ====================================


class VideoCatalogVO(BaseVO):
    dict_attrs = ['id', 'name', 'type']

    def __init__(self, model):
        self.type = 1
        super().__init__(model)


class ChapterCatalogVO(BaseVO):
    # dict_attrs = ['id', 'name', 'children']
    model_map_vo = {
        'children': VideoCatalogVO
    }

    def __init__(self, model: BaseModel):
        self.id = model.id
        self.name = model.name
        self.type = 2
        self.children = model.videos


class CourseCatalogVO(BaseVO):
    # dict_attrs = ['id', 'name', 'children'] # 全部返回可以不指定
    model_map_vo = {
        'children': ChapterCatalogVO
    }

    def __init__(self, model: BaseModel):
        self.id = model.id
        self.name = model.name
        self.type = 3
        self.children = model.chapters


# =================== create pure =========

class CreatePureVO(BaseVO):
    dict_attrs = ['id', 'name', 'type']

    def __init__(self, model, type):
        self.type = type
        super().__init__(model)
